#pragma once
#include "dictionary_tree.h"

namespace algorithm4cpp {

	template<typename TAG>
	class name_searcher : public dictionary_tree<TAG>::tree_listener
	{
	private:
		typedef dictionary_tree<TAG> dictionary;

		typedef set<dictionary*>	tree_set;
		typedef hash_map<wchar_t, tree_set> node_map;
		typedef set<TAG>	tag_set;
		typedef shared_ptr<dictionary>	tree_ptr;

	public:
		name_searcher(void)
			: nodes_()
			, tree_(0)
		{
			tree_.listener(this);
		}
		~name_searcher(void){}

	public:
		void add_name_object( const wstring& name, TAG o )
		{
			tree_.merge( name, o );
		}

		void remove_named_object( const wstring & name, TAG o )
		{
			tree_.remove( name, o );
		}

		void search( const wstring & characters, tag_set & tags ) const
		{
			const wchar_t * head = characters.c_str();
			size_t length = characters.length();

			node_map::const_iterator it = nodes_.find( *head );
			if ( it == nodes_.end() ) {
				return ;
			}

			const tree_set & trees = it->second;
			for ( tree_set::const_iterator tree = trees.begin(); tree != trees.end(); ++tree ) {
				if ( length == 1 ) {
					(*tree)->get_all_tags(tags);
					continue ;
				}

				vector<tree_ptr> p;
				(*tree)->find_path( head + 1, length - 1, p );
				if ( p.size() == length - 1 ) {
					p[p.size() - 1]->get_all_tags(tags);
				}
			}
		}

	public:
		virtual void on_tree_appended( dictionary* tree )
		{
			nodes_[tree->head()].insert( tree );
		}

		virtual void on_tree_removed( dictionary* tree )
		{
			if ( nodes_.find(tree->head() ) == nodes_.end() ) {
				assert( false );
				return ;
			}

			nodes_[tree->head()].erase(tree);
			if ( nodes_[tree->head()].empty() ) {
				nodes_.erase(tree->head());
			}
		}

	private:
		node_map	nodes_;
		dictionary	tree_;
	};

}
